package util

import (
	"encoding/json"
	"fmt"
	"github.com/pkg/errors"
	"math/big"
	"platon-tools/go-service/common/constant"
	"platon-tools/go-service/monitor/utile"
	"strconv"
)

type argInt []int

func (a argInt) Get(i int, args ...int) (r int) {
	if i >= 0 && i < len(a) {
		r = a[i]
	} else if len(args) > 0 {
		r = args[0]
	}
	return
}

func ToString(value interface{}, args ...int) (s string) {

	if value == nil {
		return "<nil>"
	}

	switch v := value.(type) {
	case bool:
		s = strconv.FormatBool(v)
	case float32:
		s = strconv.FormatFloat(float64(v), 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 32))
	case float64:
		s = strconv.FormatFloat(v, 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 64))
	case int:
		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
	case int8:
		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
	case int16:
		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
	case int32:
		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
	case int64:
		s = strconv.FormatInt(v, argInt(args).Get(0, 10))
	case uint:
		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
	case uint8:
		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
	case uint16:
		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
	case uint32:
		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
	case uint64:
		s = strconv.FormatUint(v, argInt(args).Get(0, 10))
	case string:
		s = v
	case []byte:
		s = string(v)
	case struct{}:
		stringBytes, _ := json.Marshal(value)
		s = string(stringBytes)
	case interface{}:
		stringBytes, _ := json.Marshal(value)
		s = string(stringBytes)
	default:
		s = fmt.Sprintf("%#v", v)
	}
	return s
}

// ToFloat convert the input string to a float, or 0.0 if the input is not a float.
//interface to float64
func ToFloat64(ifData interface{}) (result float64, err error) {
	switch realData := ifData.(type) {
	case float64:
		result = realData
	case float32:
		result = float64(realData)
	case int:
		result = float64(realData)
	case uint16:
		result = float64(realData)
	case uint64:
		result = float64(realData)
	case int64:
		result = float64(realData)
	case string:
		result, err = strconv.ParseFloat(realData, 64)
	default:
		err = errors.WithMessage(nil, fmt.Sprintf("%T to float64 is not support", ifData))
	}

	return result, err
}

// 单位换算
func ToLat(coin uint64) float64 {
	value := big.NewInt(0).SetUint64(coin)
	reward, _ := utile.ToEther(value).Float64()
	return reward
}

func InArray(target string, array []string) bool {
	for _, v := range array {
		if target == v {
			return true
		}
	}
	return false
}

func ConvertMonitorStatus(monitorStatus string) int {
	switch monitorStatus {
	case "Running", "Succeeded":
		return constant.NODE_MONITOR_STATUS_RUNNING
	default:
		return constant.NODE_MONITOR_STATUS_FATAL
	}
}

func ToKiB(monitorValue string) float64 {

	if len(monitorValue) <= 2 {
		return 0
	}

	valueStr := monitorValue[:len(monitorValue)-2]
	valueUnit := monitorValue[len(monitorValue):]
	value, err := ToFloat64(valueStr)
	if err != nil {
		return 0
	}
	switch valueUnit {
	case "Ki", "ki":
		return value
	case "Mi", "mi":
		return 1024 * value
	case "Gi", "gi":
		return 1024 * 1024 * value
	}
	return 0
}

func FormatByteToString(fileSize float64) (size string) {
	if fileSize < 1024 {
		//return strconv.FormatInt(fileSize, 10) + "B"
		return fmt.Sprintf("%.2fB", fileSize/float64(1))
	} else if fileSize < (1024 * 1024) {
		return fmt.Sprintf("%.2fKB", fileSize/float64(1024))
	} else if fileSize < (1024 * 1024 * 1024) {
		return fmt.Sprintf("%.2fMB", fileSize/float64(1024*1024))
	} else if fileSize < (1024 * 1024 * 1024 * 1024) {
		return fmt.Sprintf("%.2fGB", fileSize/float64(1024*1024*1024))
	} else if fileSize < (1024 * 1024 * 1024 * 1024 * 1024) {
		return fmt.Sprintf("%.2fTB", fileSize/float64(1024*1024*1024*1024))
	} else { //if fileSize < (1024 * 1024 * 1024 * 1024 * 1024 * 1024)
		return fmt.Sprintf("%.2fEB", fileSize/float64(1024*1024*1024*1024*1024))
	}
}
